/*
 * CS_DUNGEON_CLEAR_INFO.cpp
 *
 *  Created on: 2013. 5. 21.
 *      Author: the2
 */

#include "../../Command.h"

#include "../../User.h"

#include <math.h>

#include "../../xldata/rank.h"
#include "../../xldata/rank_score.h"

//#include "../../NLogic/Level.h"
#include "../../NLogic/Space.h"
#include "../../NLogic/Battle.h"
#include "../../NLogic/Function.h"
#include "../../NResource/Static.h"
#include "../../GameLog.h"

namespace ProjectZ { namespace NCommand {
//
//#define PARTY_RANK_SCORE_CONST1		100	// 파티원이 1명일 경우 산출 한 Rank값이 x1
//#define PARTY_RANK_SCORE_CONST2		60	// 파티원이 2명일 경우 산출 한 Rank값이 x0.6
//#define PARTY_RANK_SCORE_CONST3		40	// 파티원이 3명일 경우 산출 한 Rank값이 x0.4
//
//int GetRank(User * pUser, NLogic::Space * pSpace)
//{
//	int table_id = pSpace->GetData()._table_id;
//	int player_count = pSpace->GetUserTree().size();
//
//	const NXLData::RANK_SCORE_RANK_SCORE_CONDITION *point = &NXLData::stRank_Score_Rank_Score_Condition[0];
//	const NXLData::RANK_SCORE_RANK_SCORE_CONDITION *data  = &NXLData::stRank_Score_Rank_Score_Condition[table_id];
//
//	int rank_point = 0;
//
//	// 던전 클리어 타임
//	if (pUser->GetBattle()->GetData().clear_second <= data->CLEAR_TIME1)
//	{
//		rank_point += point->CLEAR_TIME1;
//	}
//	else if (pUser->GetBattle()->GetData().clear_second <= data->CLEAR_TIME2)
//	{
//		rank_point += point->CLEAR_TIME2;
//	}
//	else if (pUser->GetBattle()->GetData().clear_second <= data->CLEAR_TIME3)
//	{
//		rank_point += point->CLEAR_TIME3;
//	}
//
//	// 최대 콤보
//	if (pUser->GetBattle()->GetData().combo_max >= data->MAX_COMBO1)
//	{
//		rank_point += point->MAX_COMBO1;
//	}
//	else if (pUser->GetBattle()->GetData().combo_max >= data->MAX_COMBO2)
//	{
//		rank_point += point->MAX_COMBO2;
//	}
//	else if (pUser->GetBattle()->GetData().combo_max >= data->MAX_COMBO3)
//	{
//		rank_point += point->MAX_COMBO3;
//	}
//
//	// 누적 피해
//	if (pUser->GetBattle()->GetData().acc_damage >= data->ACC_DAMEGE_TO_MOB1)
//	{
//		rank_point += point->ACC_DAMEGE_TO_MOB1;
//	}
//	else if (pUser->GetBattle()->GetData().acc_damage >= data->ACC_DAMEGE_TO_MOB2)
//	{
//		rank_point += point->ACC_DAMEGE_TO_MOB2;
//	}
//	else if (pUser->GetBattle()->GetData().acc_damage >= data->ACC_DAMEGE_TO_MOB3)
//	{
//		rank_point += point->ACC_DAMEGE_TO_MOB3;
//	}
//
//	// 몬스터 처치
//	if (pUser->GetBattle()->GetData().kill_monster_num >= data->MAX_KILLMONSTER1)
//	{
//		rank_point += point->MAX_KILLMONSTER1;
//	}
//	else if (pUser->GetBattle()->GetData().kill_monster_num >= data->MAX_KILLMONSTER2)
//	{
//		rank_point += point->MAX_KILLMONSTER2;
//	}
//	else if (pUser->GetBattle()->GetData().kill_monster_num >= data->MAX_KILLMONSTER3)
//	{
//		rank_point += point->MAX_KILLMONSTER3;
//	}
//
//	// 받은 피해
//	if (pUser->GetBattle()->GetData().acc_get_damage <= data->ACC_DAMAGE_TO_PC1)
//	{
//		rank_point += point->ACC_DAMAGE_TO_PC1;
//	}
//	else if (pUser->GetBattle()->GetData().acc_get_damage <= data->ACC_DAMAGE_TO_PC2)
//	{
//		rank_point += point->ACC_DAMAGE_TO_PC2;
//	}
//	else if (pUser->GetBattle()->GetData().acc_get_damage <= data->ACC_DAMAGE_TO_PC3)
//	{
//		rank_point += point->ACC_DAMAGE_TO_PC3;
//	}
//
//	// 보스 몬스터 피해
//	if (pUser->GetBattle()->GetData().acc_damage_boss_damage >= data->ACC_DAMAGE_TO_BOSS1)
//	{
//		rank_point += point->ACC_DAMAGE_TO_BOSS1;
//	}
//	else if (pUser->GetBattle()->GetData().acc_damage_boss_damage >= data->ACC_DAMAGE_TO_BOSS2)
//	{
//		rank_point += point->ACC_DAMAGE_TO_BOSS2;
//	}
//	else if (pUser->GetBattle()->GetData().acc_damage_boss_damage >= data->ACC_DAMAGE_TO_BOSS3)
//	{
//		rank_point += point->ACC_DAMAGE_TO_BOSS3;
//	}
//
//	// 파티원의 수에 따라 랭크 계산
//	if (player_count == 1)
//	{
//		rank_point = rank_point * (PARTY_RANK_SCORE_CONST1 / 100.0);
//	}
//	else if (player_count == 2)
//	{
//		rank_point = rank_point * (PARTY_RANK_SCORE_CONST2 / 100.0);
//	}
//	else if (player_count == 3)
//	{
//		rank_point = rank_point * (PARTY_RANK_SCORE_CONST3 / 100.0);
//	}
//
//	if (rank_point > 15)
//	{
//		rank_point = 15;
//	}
//
//	int idx		= NXLData::RANK_RANK_MAX - 1;
//	int rank	= NXLData::RANK_RANK_MAX - 1;
//
//	for ( ; rank >= 0; rank--)
//	{
//		int rank_min = NXLData::stRank_Rank[idx - rank].SCORE_MIN3;
//		int rank_max = NXLData::stRank_Rank[idx - rank].SCORE_MAX2;
//
//		if (rank_min <= rank_point && rank_point <= rank_max)
//		{
//			break;
//		}
//	}
//
//	return rank;
//}

int GetBonusExp(User * pUser, NLogic::Space * pSpace, int rank)
{
	int level_avg		= 0;
	int level_sum		= 0;
	int my_level		= 0;

	NResource::BalanceData * pBalance = NResource::Static::InstancePtr()->GetBalance()->GetBalancePtr(pUser);
	if (NULL == pBalance)
	{
		DEBUGLOG("%s:%s -> pBalance is NULL!", __FILE__, __FUNCTION__);
		return 0;
	}

	const NLogic::Space::USERTREE & clsUserTree = pSpace->GetUserTree();

	NLogic::Space::USERTREE::const_iterator iter = clsUserTree.begin();
	// 파티원 수의 레벨 합계 계산
	for ( ; iter != clsUserTree.end(); iter++)
	{
		level_sum += pUser->GetCharacterInfo().level;

		if ((*iter).first == pUser->GetUserSeq())
		{
			my_level = pUser->GetCharacterInfo().level;
		}
	}

	// 파티원 수에 따라 가중치 부여
	int add_player_const = 100;
	int player_count = clsUserTree.size();

	switch (player_count)
	{
	case 1 : add_player_const = (add_player_const * pBalance->GetValue(EM_USER1_MOB_EXP_CONST)) / 100; break;
	case 2 : add_player_const = (add_player_const * pBalance->GetValue(EM_USER2_MOB_EXP_CONST)) / 100; break;
	case 3 : add_player_const = (add_player_const * pBalance->GetValue(EM_USER3_MOB_EXP_CONST)) / 100; break;
	}

	// 평균 레벨 계산
	if (player_count > 0)
	{
		level_avg = level_sum / player_count;
	}
	else
	{
		level_avg = 1;
		player_count = 1;
	}

	// 파티 구성원별 기본 경험치
	// 누적 경험치 * 본인레벨 / 파티평균레벨 * 파티원 수
	//::ProjectZ::NGame::STDungeonResultPersonal *result = pSpace->pDungeonResultPersonal[pUser->GetGID()];
	int base_exp = pUser->GetBattle()->GetData().hunting_exp * my_level / level_avg * player_count;

	// 랭크 경험치
	int rank_idx = NXLData::RANK_RANK_MAX - rank - 1;
	int rank_exp = NXLData::stRank_Rank[rank_idx].RANK_EXP_CONST4;

	// 던전 클리어 보상 경험치
	NResource::DungeonData::Flyweight * pFly =
			NResource::Static::InstancePtr()->GetDungeon()->GetFly(pUser->GetUserInfo().company, pUser->GetUserInfo().sale_code, pSpace->GetData()._table_id);

	if (NULL == pFly)
	{
		DEBUGLOG("CS_DUNGEON_CLEAR_INFO::GetBonusExp NULL == pFly");
		return 0;
	}

	int clear_exp = pFly->DUNGEON_EXP;

	// TODO - 이벤트 보너스 가중치 계산
	int event_exp = 0;
	int get_bonus_exp = base_exp * ( (add_player_const) / 100.0 ) * ( (100 + event_exp) / 100.0 ) * (rank_exp / 100.0) + clear_exp;

	return get_bonus_exp;
}

void Command::CS_DUNGEON_CLEAR_INFO(User * pUser, ::Network::Packet * pPacket)
{
	/*
	 * /// 던전 클리어 창 정보 요청
	CS_DUNGEON_CLEAR_INFO		0x1112
	{
		u32	gid;
	}

	SC_DUNGEON_CLEAR_INFO		0x1113
	{
		u8	rank;			// 0:c, 1:b, 2:a, 3:s 4:ss 5: sss 랭크 시스템 에따라서
		u16	current_level;		// 보상받은 후 현재 레벨
		u32	maxexp;		// 현재 레벨 기준 다음레벨업 까지에 경험치
		u32	total_get_exp;		// 경험치 총 증가량
		u32	hunting_exp;		// 사냥 경험치
		u32	bonus_exp;		// 보너스 경험치
		u8	exp_option;		// 하위4비트 사용(파티 / 아바타 / 부스터 / 이벤트)
		u32	clear_second;		// 클리어 시간 초단위
		u16	combo_max;		// 최대 콤보
		u32	acc_damage;		// 누적 데미지
		u16	kill_monster_num;	// 처치 몬스터 수
		u32	get_gold;		// 획득 골드량
	}

	 */
	NLogic::Space * pSpace = pUser->GetSpace();
	if (NULL == pSpace)
	{
		DEBUGLOG("CS_DUNGEON_CLEAR_INFO NULL == pSpace");
		return;
	}

	if (false == pSpace->IsDungeon())
	{
		DEBUGLOG("CS_DUNGEON_CLEAR_INFO space is not single or party dungeion");
		return;
	}


	if( true != pSpace->GetEndEungeon())
	{
		::Logger::GETLOG()->ToFile(::Logger::OBSERVER, "HACK> CS_DUNGEON_CLEAR_INFO()> userseq: %d> The boss is alive. the dungeon is not ended!", pUser->GetUserSeq());
		::Logger::GETLOG()->ToFile(::Logger::OBSERVER, "CS_DUNGEON_CLEAR_INFO()> userseq: %d, isEnd: %d, #monster: %d, #dead: %d, #kill: %d, totalDamageToBoss: %d, _starttick %d, _finishtick: %d"
				, pUser->GetUserSeq(), pSpace->GetEndEungeon(), pSpace->GetMonsterCount(), pSpace->GetDeadMonsterTree().size()
				, pUser->GetBattle()->GetData().kill_monster_num, pUser->GetSpace()->GetData()._totalDamageToBoss
				, pSpace->GetData()._starttick, pSpace->GetData()._finishtick );
		return;
	}




	if (true == pUser->GetBattle()->GetData()._dungeonReward)
	{
		DEBUGLOG("CS_DUNGEON_CLEAR_INFO true == pUser->GetBattle()->GetData()._dungeonReward");
		return;
	}

	PREPARE_PACKET;
	pUser->GetBattle()->GetData().clear_second = (pSpace->GetData()._finishtick - pSpace->GetData()._starttick);

	pUser->GetBattle()->GetData().acc_damage_boss_percent
			= floor((float)pUser->GetBattle()->GetData().acc_damage_boss_damage / (float)pSpace->GetData()._totalDamageToBoss * 100 + 0.5f);
	//strcpy(result->nickname, pUser->GetUserInfo().nickname.c_str());

	// calc rank
	//pUser->GetBattle()->GetData().rank = GetRank(pUser, pSpace);
	//pUser->GetBattle()->GetData().rank = NLogic::NFunction::GetRank(pUser, pSpace);

	pUser->GetBattle()->GetData().bonus_exp = GetBonusExp(pUser, pSpace, pUser->GetBattle()->GetData().rank);

	// 이벤트 여부를 확인하여 경험치 가중치 적용
	int addExp = NResource::Static::InstancePtr()->GetDungeonEvent()->GetWeightExp(pUser);
	pUser->GetBattle()->GetData().bonus_exp = (pUser->GetBattle()->GetData().bonus_exp * addExp) / 100;
	pUser->GetBattle()->GetData().hunting_exp = (pUser->GetBattle()->GetData().hunting_exp * addExp) / 100;

	pUser->GetBattle()->GetData().total_get_exp = pUser->GetBattle()->GetData().hunting_exp + pUser->GetBattle()->GetData().bonus_exp;

	// calc new level
	ProjectZ::NLogic::NFunction::IncreaseExp(pUser, pUser->GetBattle()->GetData().total_get_exp);


	NResource::DungeonData::Flyweight * pFly =
			NResource::Static::InstancePtr()->GetDungeon()->GetFly(pUser->GetUserInfo().company, pUser->GetUserInfo().sale_code, pSpace->GetData()._table_id);
	if (NULL == pFly)
	{
		DEBUGLOG("CS_DUNGEON_CLEAR_INFO : pFly is NULL!!");
		return;
	}

	// 던전 획득 골드 + 던전 클리어 보상 골드
	pUser->GetBattle()->GetData().get_gold += pFly->DUNGEON_GOLD;

	// 이벤트 여부를 확인하여 골드 가중치 적용
	int addGold = NResource::Static::InstancePtr()->GetDungeonEvent()->GetWeightGold(pUser);
	pUser->GetBattle()->GetData().get_gold = (pUser->GetBattle()->GetData().get_gold * addGold) / 100;

//	pUser->GetCharacterInfo().gold += pUser->GetBattle()->GetData().get_gold;

	int maxGold = NResource::Static::Instance().GetMaxGainGoldResource()->GetMaxGold(pSpace->GetData()._table_id);
	if (maxGold < pUser->GetBattle()->GetData().get_gold)
	{
		DEBUGLOG("MAXGAINGOLD OVER GOLD : %d GID : %d", pUser->GetBattle()->GetData().get_gold, pUser->GetUserSeq());
		pUser->GetBattle()->GetData().get_gold = maxGold;
	}


	NLogic::NFunction::ModifyGold(pUser, pUser->GetBattle()->GetData().get_gold);
	NGameLog::LogGoldInfo(pUser, DUNGEON_CLEAR, pUser->GetBattle()->GetData().get_gold);

	// send
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	pAck->Write1(pUser->GetBattle()->GetData().rank);					//u8	rank;			// 0 : s 1 : aaa 랭크 시스템 에따라서
	pAck->Write2(pUser->GetCharacterInfo().level);			//u16	current_level;		// 보상받은 후 현재 레벨
	pAck->Write4(::ProjectZ::NLogic::NFunction::getMaxExp(pUser));			//u8	exp_rate;		// 현재 레벨 기준 다음레벨업 까지 획득한 경험치 백분율
	* pAck << pUser->GetBattle()->GetData().total_get_exp;		//u32	total_get_exp;		// 경험치 총 증가량
	* pAck << pUser->GetBattle()->GetData().hunting_exp;		//u32	hunting_exp;		// 사냥 경험치
	* pAck << pUser->GetBattle()->GetData().bonus_exp;		//u32	bonus_exp;		// 보너스 경험치

	if (true == pSpace->IsPartyDungeon())
	{
		pUser->GetBattle()->GetData().exp_option |= 8;
	}

	if (addExp > 100)
	{
		pUser->GetBattle()->GetData().exp_option |= 1;
	}

	pAck->Write1(pUser->GetBattle()->GetData().exp_option);		//u8	exp_option;		// 하위4비트 사용(파티 / 아바타 / 부스터 / 이벤트)

	* pAck << pUser->GetBattle()->GetData().clear_second;		//u32	clear_second;		// 클리어 시간 초단위
	pAck->Write2(pUser->GetBattle()->GetData().combo_max);		//u16	combo_max;		// 최대 콤보
	* pAck << pUser->GetBattle()->GetData().acc_damage;		//u32	acc_damage;		// 누적 데미지
	pAck->Write2(pUser->GetBattle()->GetData().kill_monster_num);		//u16	kill_monster_num;	// 처치 몬스터 수
	* pAck << pUser->GetBattle()->GetData().get_gold;		//u32	get_gold;		// 획득 골드량

	pAck->MakePacket(CMD_SC_DUNGEON_CLEAR_INFO);
	pUser->Send(pAck);

	pUser->GetBattle()->GetData()._dungeonReward = true;
}



} /*NCommand*/ } /*ProjectZ*/
